/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 *
 * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
 *
 * Contributor(s): 
 *  Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
 *  
 * If you didn't download this code from the following link, you should check
 * if you aren't using an obsolete version: http://www.isqlviewer.com
 */
package org.isqlviewer.model;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import javax.swing.tree.DefaultMutableTreeNode;

/**
 * TreeNode class for distinguinshing different nodes by a given type within a tree.
 * <p>
 * This node class should alleviate and provide more flexiblility to the structure of the JdbcSchema tree so that nodes
 * can be indentified by an enumerated type instead of making a guess by the name of the node itself as to what data it
 * actually represents in the JDBC Schema.
 * 
 * @author Mark A. Kobold &lt;mkobold at isqlviewer dot com&gt;
 * @version 1.0
 */
public final class SchemaNode extends DefaultMutableTreeNode implements Transferable {

    public static final String MIME_TYPE = "java-x-object/org.isqlviewer.model.SchemaNode";
    public static final DataFlavor DATA_FLAVOR = new DataFlavor(SchemaNode.class, MIME_TYPE);

    private static final long serialVersionUID = 1L;
    private SchemaNodeType nodeType = null;
    private boolean hasError = false;

    private static DataFlavor[] supportedDataFlavors;

    static {
        supportedDataFlavors = new DataFlavor[2];
        supportedDataFlavors[0] = DATA_FLAVOR;
        supportedDataFlavors[1] = DataFlavor.stringFlavor;
    }

    /**
     * Creates a tree node that has no parent and no children, but which allows children.
     * <p>
     * 
     * @param nodeType type of node this instance represents.
     * @throws NullPointerException if nodeType is null.
     */
    public SchemaNode(SchemaNodeType nodeType) {

        this(null, true, nodeType);
    }

    /**
     * Creates a tree node with no parent, no children.
     * <p>
     * This instance will be one that allows children, and initializes it with the specified user object.
     * 
     * @param userObject an Object provided by the user that constitutes the node's data
     * @param nodeType type of node this instance represents.
     * @throws NullPointerException if nodeType is null.
     */
    public SchemaNode(Object userObject, SchemaNodeType nodeType) {

        this(userObject, true, nodeType);
    }

    /**
     * Creates a tree node with no parent, no children.
     * <p>
     * This instance will be initialized with the specified user object, and that allows children only if specified.
     * 
     * @param userObject an Object provided by the user that constitutes the node's data
     * @param allowsChildren if true, the node is allowed to have child nodes -- otherwise, it is always a leaf node
     * @param nodeType type of node this instance represents.
     * @throws NullPointerException if nodeType is null.
     */
    public SchemaNode(Object userObject, boolean allowsChildren, SchemaNodeType nodeType) {

        super(userObject, allowsChildren);
        if (nodeType == null) {
            throw new NullPointerException();
        }
        this.nodeType = nodeType;
    }

    /**
     * Gets the current type of schema node this represenents.
     * <p>
     * 
     * @return type of node within the JDBC Schema is being represented.
     */
    public SchemaNodeType getNodeType() {

        return nodeType;
    }

    /**
     * Return true if this node loaded with an error.
     * <p>
     * Since most schema nodes are loaded via the database this allows a state to be saved to the node if parent or
     * child had an error during the loading process.
     * 
     * @return <tt>true</tt> if this node expierenced some sort of SQL Exception during initialization.
     */
    public boolean isHasError() {

        return hasError;
    }

    /**
     * @return
     */
    public boolean isNoncached() {

        if (nodeType == SchemaNodeType.NON_CACHED) {
            return true;
        }
        if (allowsChildren && (children != null && children.size() > 0)) {
            SchemaNode firstChild = (SchemaNode) children.get(0);
            return firstChild == null ? false : firstChild.isNoncached();
        }
        return false;
    }

    @Override
    public String getUserObject() {

        Object obj = super.getUserObject();
        return obj == null ? "" : obj.toString();
    }

    /**
     * Sets the error flag to the appropriate value.
     * <p>
     * 
     * @param hasError value to indicate if the node expierenced and error.F
     */
    public synchronized void setHasError(boolean hasError) {

        this.hasError = hasError;
    }

    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {

        if (flavor != null) {
            if (flavor.equals(supportedDataFlavors[0])) {
                return this;
            } else if (flavor.equals(supportedDataFlavors[1])) {
                return toString();
            }
        }
        throw new UnsupportedFlavorException(flavor);
    }

    public DataFlavor[] getTransferDataFlavors() {

        return supportedDataFlavors;
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {

        if (flavor != null) {
            if (flavor.equals(supportedDataFlavors[0])) {
                return true;
            } else if (flavor.equals(supportedDataFlavors[1])) {
                return true;
            }
        }
        return false;
    }

}